package study.spring.core.ioc._3_bean_assemble;

import study.spring.core.ioc._3_bean_assemble.multiimpl.AssembleMultiImplClass;
import study.spring.core.ioc._3_bean_assemble.propertyAssemble.InjectWithConstructInjection;
import study.spring.core.ioc._3_bean_assemble.propertyAssemble.InjectWithSetMethodInjection;
import study.spring.core.ioc._3_bean_assemble.singletonuseprototype.ErrorPrototypeBean;
import study.spring.core.ioc._3_bean_assemble.singletonuseprototype.RightPrototypeBean;
import study.spring.core.ioc._3_bean_assemble.singletonuseprototype.SingletonBeanForSpring;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
@Slf4j
public class SpringBeanAssemble {

  // 演示 spring 容器中, 各个对象之间依赖注入属
  public static void main(String[] args) {
    oneInterfaceMultiImplHowAutowired();
//    injectWithSetMethodVSConstruct();
//    singletonHasPrototypeProperty();
  }

  /**
   * 如果一个接口有多个实现类, 该如何正确注入属性值
   * <p>
   * 1. 属性名使用实现类的名称 {@link AssembleMultiImplClass#multiImplementsOne}
   * <p>
   * 2. 使用 @Primary
   */
  static void oneInterfaceMultiImplHowAutowired() {
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringBeanAssemble.class);
    AssembleMultiImplClass assembleClass = context.getBean(AssembleMultiImplClass.class);
  }

  /**
   * Set 方法注入属性  VS  构造器注入属性
   */
  static void injectWithSetMethodVSConstruct() {
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringBeanAssemble.class);
    InjectWithSetMethodInjection bean = context.getBean(InjectWithSetMethodInjection.class);
    InjectWithConstructInjection bean1 = context.getBean(InjectWithConstructInjection.class);
    System.out.println(bean);
    System.out.println(bean1);
  }

  /**
   * 单例 bean 有一个属性是 原型 bean, 如何正确注入
   */
  private static void singletonHasPrototypeProperty() {
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringBeanAssemble.class);
    SingletonBeanForSpring bean = context.getBean(SingletonBeanForSpring.class);
    log.info("单例bean的hashcode:{}", bean.hashCode());
    RightPrototypeBean rightBean = bean.getRightPrototypeBean();
    log.info("正确的引用非单例:{}, hashcode:{}", rightBean.getClass().getSimpleName(), rightBean.hashCode());
    ErrorPrototypeBean errorBean = bean.errorPrototypeBean;
    log.info("错误的引用非单例:{}, hashcode:{}", errorBean.getClass().getSimpleName(), errorBean.hashCode());

    SingletonBeanForSpring bean2 = context.getBean(SingletonBeanForSpring.class);
    log.info("单例bean的hashcode:{}", bean2.hashCode());
    RightPrototypeBean rightBean2 = bean2.getRightPrototypeBean();
    log.info("正确的引用非单例:{}, hashcode:{}", rightBean2.getClass().getSimpleName(), rightBean2.hashCode());
    ErrorPrototypeBean errorBean2 = bean2.errorPrototypeBean;
    log.info("错误的引用非单例:{}, hashcode:{}", errorBean2.getClass().getSimpleName(), errorBean2.hashCode());


  }
}
